<script lang="ts" setup>
import { ref, watch, defineEmits, nextTick } from 'vue'
import { ElMessageBox } from 'element-plus'
import { Search } from '@element-plus/icons-vue'
import { has } from 'lodash'
import PinYinMatch from 'pinyin-match'
// 入参
const props = defineProps({
  // 数据源
  treeData: Array,
  // 树组件props
  treeProps: {
    type: Object,
    default: () => {
      return {
        children: 'children',
        label: 'mc',
      }
    },
  },
  // 是否为树状节点,不是树节点不显示新增按钮
  isTreeNode: {
    type: Boolean,
    default: false,
  },
  // 定义节点模板
  nodeTemplate: {
    type: Object,
  },
  // 节点标识
  nodeKey: {
    type: String,
    default: 'bm',
  },
  // 父节点标识
  parentNodeKey: {
    type: String,
    default: 'fbm',
  },
  defaultExpandAll: {
    type: Boolean,
    default: true,
  },
})
const emit = defineEmits(['treeNodeClick', 'deleteTreeNode', 'saveTreeData', 'cancelNodeChange'])
const treeList = ref<any>([])
const defaultExpandedKeys = ref<string[]>([])

/* 验证是否首次使用 */
const isFirst = ref(true)
watch(
  () => props.treeData,
  (newVal) => {
    treeList.value = newVal
    if (props.defaultExpandAll && isFirst.value && treeList.value.length) {
      isFirst.value = false
      defaultExpandedKeys.value = treeList.value.map((el: any) => el[props.nodeKey])
    }
  },
  {
    immediate: true,
  },
)
/*
 * 添加一级目录
 */
const inputRef = ref()
const addMl = () => {
  // obj外部传参，判断一下，如果isAdd为true，则不添加
  const len = treeList.value.length
  if (len > 0 && treeList.value[0].isAdd) {
    return
  }
  treeList.value.unshift({
    ...props.nodeTemplate,
    isAdd: true,
    [props.nodeKey]: `empty-${Date.now()}`,
  })
  nextTick(() => {
    inputRef.value.focus()
  })
}

/*
 * 添加下级目录
 */
const addChild = (data: any, node: any) => {
  if (has(data, 'children') && Array.isArray(data.children)) {
    // 判断一下
    const len = data.children.length
    if (len > 0 && data.children[0].isAdd) {
      return
    }
    defaultExpandedKeys.value.push(data[props.nodeKey])
    node.expanded = true
    data.children.unshift({
      ...props.nodeTemplate,
      isAdd: true,
      [props.parentNodeKey]: data[props.nodeKey],
      [props.nodeKey]: `empty-${Date.now()}`,
    })
  } else {
    defaultExpandedKeys.value.push(data[props.nodeKey])
    node.expanded = true
    data.children = [
      {
        ...props.nodeTemplate,
        isAdd: true,
        [props.parentNodeKey]: data[props.nodeKey],
        [props.nodeKey]: `empty-${Date.now()}`,
      },
    ]
  }
  beforeLeave()
  setTimeout(() => {
    inputRef.value.focus()
  }, 100)
}

/*
 * 修改目录
 */
const editorMl = (data: any) => {
  data.cloneMc = data[props.treeProps.label]
  data.isAdd = true
  beforeLeave()
  setTimeout(() => {
    inputRef.value.focus()
  }, 100)
}

/**
 * 修改/新增选中后回调
 */

const checkMl = (data: any) => {
  if (!data.cloneMc) {
    closeMl(data)
    return
  }
  if (!data.isAdd) return
  data.isAdd = false
  emit('saveTreeData', {
    ...data,
    [props.treeProps.label]: data.cloneMc,
  })
}

/**
 * 修改/新增取消后回调
 */
const closeMl = (data: any) => {
  data.isAdd = false
  // 这里判断是否是新增的
  if (data[props.nodeKey].startsWith('empty')) {
    treeRef.value.remove(data)
  }
}
/*
 * 删除目录（抛出事件）
 */
const deleteMl = (data: any) => {
  beforeLeave()
  ElMessageBox.confirm('是否删除当前选中节点？', '删除提示', {
    confirmButtonText: '删除',
    cancelButtonText: '取消',
    type: 'warning',
  }).then(() => {
    emit('deleteTreeNode', data)
  })
}

/*
 * 筛选树
 */
const filterText = ref<string>('')
const treeRef = ref()
// 监听筛选输入
watch(filterText, (val) => {
  treeRef.value.filter(val)
})
// 筛选树方法
const filterTree = (value: string, data: any) => {
  if (!value) return true
  return (
    data[props.treeProps.label].includes(value) ||
    PinYinMatch.match(data[props.treeProps.label], value)
  )
}

/*
 * 树点击（抛出事件）
 */
const nodeClick = (data: any) => {
  if (data[props.nodeKey].startsWith('empty')) {
    return
  }
  emit('treeNodeClick', data)
}

/* propover框强制关闭，elementPlus的bug */
const beforeLeave = () => {
  const dom = document.getElementsByClassName('ep-popper') as any
  for (let i = 0; i < dom.length; i++) {
    dom[i].style.display = 'none'
  }
}

/* 新增绑定默认展开节点 */
/* 展开节点 */
const nodeExpand = (data: any) => {
  defaultExpandedKeys.value.push(data[props.nodeKey])
}

/* 收起节点 */
const nodeCollapse = (data: any) => {
  const index = defaultExpandedKeys.value.findIndex((item) => item === data[props.nodeKey])
  defaultExpandedKeys.value.splice(index, 1)
}

/* 新增拖拽功能 */
const nodeDragEnter = (node: any, inNode: any, wz: string) => {
  let data = {}
  if (wz === 'inner') {
    data = {
      ...node.data,
      [props.nodeKey]: node.data[props.nodeKey],
      [props.parentNodeKey]: inNode.data[props.nodeKey],
    }
  } else {
    data = {
      ...node.data,
      [props.nodeKey]: node.data[props.nodeKey],
      [props.parentNodeKey]: inNode.data[props.parentNodeKey] || '',
    }
  }
  emit('saveTreeData', data)
}
/* 未保存的节点不能拖拽 */
const allowDrag = (node: any) => {
  if (node.data.isAdd) return false
  return true
}
/* 高亮当前节点 */
const setCurrentKey = (key: string) => {
  treeRef.value.setCurrentKey(key)
}
const showPackage = (data: any) => {
  return (
    (data.children && data.children.length > 0) || props.isTreeNode || !data[props.parentNodeKey]
  )
}
defineExpose({ addMl, setCurrentKey })
</script>
<template>
  <div class="tree-wrapper">
    <!-- 头部 -->
    <slot name="header"></slot>
    <!-- 树 -->
    <div class="tree-content">
      <el-input
        class="filterText input-search"
        v-model="filterText"
        placeholder="请输入要检索的关键字"
        maxlength="30"
        :suffix-icon="Search"
      />
      <el-tree
        ref="treeRef"
        class="filter-tree"
        :data="treeList"
        :props="treeProps"
        :node-key="nodeKey"
        :draggable="!isTreeNode"
        :expand-on-click-node="false"
        :filter-node-method="filterTree"
        :default-expanded-keys="defaultExpandedKeys"
        :allow-drag="allowDrag"
        @current-change="nodeClick"
        highlight-current
        @node-expand="nodeExpand"
        @node-collapse="nodeCollapse"
        @node-drop="nodeDragEnter"
      >
        <template #default="scope">
          <div
            class="tree-item"
            :class="{
              'tree-item-empty': scope.data.isAdd,
            }"
          >
            <el-input
              ref="inputRef"
              v-if="scope.data.isAdd"
              v-model="scope.data.cloneMc"
              maxlength="50"
              @keyup.enter.stop="checkMl(scope.data)"
              @blur.stop="checkMl(scope.data)"
            ></el-input>
            <span
              class="tree-item-label"
              :class="{
                'tree-item-pakage': showPackage(scope.data),
              }"
              :id="scope.data[nodeKey]"
              v-else
              >{{ scope.data[treeProps.label] }}</span
            >
            <!-- 操作栏 -->
            <div class="cz" v-if="!scope.data.isAdd">
              <el-popover title="" :width="120" trigger="click" @before-leave="beforeLeave">
                <ul class="popover-ul">
                  <li @click.stop="addChild(scope.data, scope.node)" v-if="!isTreeNode">
                    <el-link type="info" :underline="false">添加</el-link>
                  </li>
                  <li @click.stop="editorMl(scope.data)">
                    <el-link type="info" :underline="false">修改</el-link>
                  </li>
                  <li @click.stop="deleteMl(scope.data)">
                    <el-link type="info" :underline="false">删除</el-link>
                  </li>
                </ul>
                <template #reference>
                  <el-icon class="icon-trans"><More /></el-icon>
                </template>
              </el-popover>
            </div>
            <!-- 确认、取消按钮栏 -->
            <!-- <div class="empty-action-btns" v-else>
              <el-icon class="check" @click.stop="checkMl(scope.data)" color="green"
                ><Check
              /></el-icon>
              <el-icon class="close" @click.stop="closeMl(scope.data)" color="red"
                ><Close
              /></el-icon>
            </div> -->
          </div>
        </template>
      </el-tree>
    </div>
  </div>
</template>
<style lang="scss" scoped>
.tree-wrapper {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  .tree-content {
    flex: 1;
    height: 100%;
    display: flex;
    flex-direction: column;
  }
  .ep-tree {
    overflow-x: hidden;
    height: 100%;
    margin-top: 10px;
  }
}

:deep(.ep-tree-node__label) {
  display: flex;
  align-items: center;
  width: 100%;
  height: 100%;
}

:deep(.ep-tree-node__content .tree-item .tree-item-label) {
  &::before {
    background: url('@/assets/images/common/file.png') no-repeat center center;
    content: '';
    display: inline-block;
    width: 14px;
    height: 18px;
    margin-right: 5px;
    vertical-align: top;
  }
  &.tree-item-pakage::before {
    height: 14px;
    margin-top: 2px;
    background: url('@/assets/images/common/package.png') no-repeat center center;
  }
}
:deep().ep-tree {
  .ep-tree-node__expand-icon {
    //引入的图标（图片）size大小 => 树节点前的预留空间大小
    font-size: 14px;
    transform: rotate(-90deg);
    &.expanded {
      // -webkit-transform: rotate(0deg);
      transform: rotate(0deg);

      &:before {
        //展开的节点
        background: url('@/assets/images/common/expand.png') no-repeat center center;
        background-size: cover;
        content: '';
        display: block;
        width: 9px;
        height: 5px;
      }
    }

    &:before {
      // 未展开的节点
      background: url('@/assets/images/common/expand.png') no-repeat center center;
      background-size: cover;
      content: '';
      display: block;
      width: 9px;
      height: 5px;
    }
  }
}
:deep(.ep-tree-node__content) {
  .cz {
    width: 15px;
    visibility: hidden;
  }
  .ep-icon {
    margin-right: 5px;
  }
  &:hover {
    .cz {
      visibility: inherit;
    }
  }
  > i {
    svg {
      display: none;
      height: 0;
      width: 0;
    }
  }
}

.tree-item {
  display: flex;
  flex: 1;
  align-items: center;
  :deep(.ep-input__inner) {
    height: 22px;
    line-height: 22px;
  }

  .tree-item-label {
    flex: 1;
    width: 0;
    word-break: break-all;
    text-overflow: ellipsis;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 1;
    overflow: hidden;
    // overflow-y: hidden;
  }
}
.icon-trans {
  transform: rotate(90deg);
  cursor: pointer;
  &:hover {
    color: var(--color-light);
  }
}

// 弹出按钮
.popover-ul {
  width: 100%;
  li {
    width: 100%;
    height: 30px;
    line-height: 30px;
    text-align: center;
    cursor: pointer;
    &:hover {
      background: #f5f7fa;
    }
  }
}
.ep-link--info {
  color: var(--operation-color);
  &:hover {
    color: var(--btn-bg-primary-hover);
  }
}
</style>
